#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member

using System;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;

namespace EntityKit.Runtime
{
    /// <summary>
    /// Unity Component和GameObject的异步扩展方法
    /// </summary>
    public static class UnityAsyncExtensions
    {
        /// <summary>
        /// 等待指定的秒数（基于Unity的时间系统）
        /// </summary>
        /// <param name="component">组件</param>
        /// <param name="seconds">等待的秒数</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>Task</returns>
        public static Task WaitForSeconds(this Component component, float seconds, CancellationToken cancellationToken = default)
        {
            return WaitForSeconds(component.gameObject, seconds, cancellationToken);
        }
        
        /// <summary>
        /// 等待指定的秒数（基于Unity的时间系统）
        /// </summary>
        /// <param name="gameObject">游戏对象</param>
        /// <param name="seconds">等待的秒数</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>Task</returns>
        public static async Task WaitForSeconds(this GameObject gameObject, float seconds, CancellationToken cancellationToken = default)
        {
            if (seconds <= 0)
                return;
                
            var destroyToken = gameObject.GetGameObjectDestroyToken();
            var combinedToken = cancellationToken.CombineWith(destroyToken);
            
            var tcs = new TaskCompletionSource<bool>();
            
            // 注册取消操作
            combinedToken.Register(() => tcs.TrySetCanceled());
            
            // 使用Unity的计时器
            var startTime = Time.time;
            while (Time.time - startTime < seconds)
            {
                if (combinedToken.IsCancellationRequested)
                    break;
                await Task.Yield();
            }
            
            if (!combinedToken.IsCancellationRequested)
                tcs.TrySetResult(true);
                
            await tcs.Task;
        }
        
        /// <summary>
        /// 等待下一帧
        /// </summary>
        /// <param name="component">组件</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>Task</returns>
        public static Task WaitForEndOfFrame(this Component component, CancellationToken cancellationToken = default)
        {
            return WaitForEndOfFrame(component.gameObject, cancellationToken);
        }
        
        /// <summary>
        /// 等待下一帧
        /// </summary>
        /// <param name="gameObject">游戏对象</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>Task</returns>
        public static Task WaitForEndOfFrame(this GameObject gameObject, CancellationToken cancellationToken = default)
        {
            var destroyToken = gameObject.GetGameObjectDestroyToken();
            var combinedToken = cancellationToken.CombineWith(destroyToken);
            
            var tcs = new TaskCompletionSource<bool>();
            combinedToken.Register(() => tcs.TrySetCanceled());
            
            // 创建一个MonoBehaviour来等待帧结束
            var waiter = gameObject.AddComponent<FrameWaiter>();
            waiter.WaitForEndOfFrame(() => tcs.TrySetResult(true), combinedToken);
            
            return tcs.Task;
        }
        
        /// <summary>
        /// 等待条件满足
        /// </summary>
        /// <param name="component">组件</param>
        /// <param name="condition">条件函数</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>Task</returns>
        public static Task WaitForCondition(this Component component, System.Func<bool> condition, CancellationToken cancellationToken = default)
        {
            return WaitForCondition(component.gameObject, condition, cancellationToken);
        }
        
        /// <summary>
        /// 等待条件满足
        /// </summary>
        /// <param name="gameObject">游戏对象</param>
        /// <param name="condition">条件函数</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>Task</returns>
        public static async Task WaitForCondition(this GameObject gameObject, System.Func<bool> condition, CancellationToken cancellationToken = default)
        {
            var destroyToken = gameObject.GetGameObjectDestroyToken();
            var combinedToken = cancellationToken.CombineWith(destroyToken);
            
            while (!condition())
            {
                if (combinedToken.IsCancellationRequested)
                    break;
                await Task.Yield();
            }
        }
    }
}